package com.cloudinnov.dao.mongo;

import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.cloudinnov.utils.mongo.MongoPage;
import com.cloudinnov.utils.mongo.ReflectionUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;

public abstract class BaseMongoDAOImpl<T> implements BaseMongoDAO<T> {
	
	@SuppressWarnings("unused")
	private static final int DEFAULT_SKIP = 0;
	@SuppressWarnings("unused")
	private static final int DEFAULT_LIMIT = 200;
	/**
	 * spring mongodb 集成操作类
	 */
	@Autowired
	protected MongoTemplate mongoTemplate;

	@Override
	public List<T> find(Query query) {
		return mongoTemplate.find(query, this.getEntityClass());
	}
	@Override
	public T findOne(Query query) {
		return mongoTemplate.findOne(query, this.getEntityClass());
	}
	@Override
	public void update(Query query, Update update) {
		mongoTemplate.findAndModify(query, update, this.getEntityClass());
	}
	@Override
	public T save(T entity) {
		mongoTemplate.insert(entity);
		return entity;
	}
	@Override
	public T findById(String id) {
		return mongoTemplate.findById(id, this.getEntityClass());
	}
	@Override
	public T findById(String id, String collectionName) {
		return mongoTemplate.findById(id, this.getEntityClass(), collectionName);
	}
	@Override
	public MongoPage<T> findPage(MongoPage<T> page, Query query) {
		long count = this.count(query);
		page.setTotal(count);
		int pageNumber = page.getPageNumber();
		int pageSize = page.getPageSize();
		query.skip((pageNumber - 1) * pageSize).limit(pageSize);
		List<T> rows = this.find(query);
		page.setRows(rows);
		return page;
	}
	@Override
	public long count(Query query) {
		return mongoTemplate.count(query, this.getEntityClass());
	}
	/**
	 * 计算某个字段是和
	 * @param collection
	 * @param filedName
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public double sumField(String collection, String filedName, Criteria criteria) {
		double total = 0l;
		String reduce = "function(doc, aggr){" + "            aggr.total += parseFloat((Math.round((doc." + filedName
				+ ")*100)/100).toFixed(2));" + "       }";
		Query query = new Query();
		if (criteria != null) {
			query.addCriteria(criteria);
		}
		DBObject result = mongoTemplate.getCollection(collection).group(null, query.getQueryObject(),
				new BasicDBObject("total", total), reduce);
		Map<String, BasicDBObject> map = result.toMap();
		if (map.size() > 0) {
			BasicDBObject bdbo = map.get("0");
			if (bdbo != null && bdbo.get("total") != null)
				total = bdbo.getDouble("total");
		}
		return total;
	}
	/**
	 * 计算某个字段是和
	 * @param collection
	 * @param filedName
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public long sumField(String filedName, Criteria... criteria) {
		long total = 0l;
		String reduce = "function(doc, aggr){" + "            aggr.total += parseInt((Math.round((doc." + filedName
				+ ")*100)/100));" + "       }";
		Query query = new Query();
		if (criteria != null) {
			for (int i = 0; i < criteria.length; i++) {
				query.addCriteria(criteria[i]);
			}
		}
		DBObject result = mongoTemplate.getCollection(mongoTemplate.getCollectionName(this.getEntityClass()))
				.group(null, query.getQueryObject(), new BasicDBObject("total", total), reduce);
		Map<String, BasicDBObject> map = result.toMap();
		if (map.size() > 0) {
			BasicDBObject bdbo = map.get("0");
			if (bdbo != null && bdbo.get("total") != null)
				total = bdbo.getLong("total");
		}
		return total;
	}
	
	/**
	 * 获取需要操作的实体类class
	 * @return
	 */
	private Class<T> getEntityClass() {
		return ReflectionUtils.getSuperClassGenricType(getClass());
	}
}
